package com.webmining.sherlock.admin;


import com.webmining.sherlock.util.search.Constants;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;

public class Configuration {
	
	private static String home = null;
	
	private static boolean loggerActive = false;

    public static String getHome() throws ConfigurationException {
    	if (home != null) {
    		return home;
    	}
        home = System.getProperty(Constants.SHERLOCK_HOME);
        if ( home == null) {
        	String msg = "Unable to locate the sherlock home " +
				"directory, please use the -D option of your java " +
				"interpreter with the " + Constants.CONFIGURATION_SHERLOCK +
				" property";
        	Logger log = Logger.getLogger(Configuration.class);
        	log.error(msg);
        	throw new ConfigurationException(msg);
        }
        return home;
    }
    
    public static void setHome(String home) {
    	Configuration.home = home;
    }
    
    public static boolean isLoggerActive() {
    	return Configuration.loggerActive;	
    }
    
    static void setLoggerActive(boolean loggerActive) {
    	Configuration.loggerActive = loggerActive;
    }
    
    /**
     * Reads the value of a property form the sherlock configuration
     * @param property name
     * @return value of the property
     */
    public static String getProperty(String property)
    		throws ConfigurationException {
        String configFilename = Constants.CONFIG_DIRECTORY + "/" +
				Constants.CONFIGURATION_SHERLOCK;
        return getProperty(configFilename, property);
    }
    /**
     * Reads the value of a property from the test configuration
     * @param property name
     * @return value of the property
     */
    public static String getTestProperty(String property)
    		throws ConfigurationException {
        String configFilename = getHome() + File.separator +
				Constants.CONFIG_DIRECTORY + File.separator +
				Constants.CONFIGURATION_TEST;
        return getProperty(configFilename, property);
    }
    
    /**
     * Reads the value of a property
     * @param configFilename file
     * @param property name
     * @return value of the property
     */
    public static String getProperty(String configFilename, String property)
    		throws ConfigurationException {
    	Logger log = Logger.getLogger(Configuration.class);
        String value;
        try {
            InputStream configFile = Configuration.class.getClassLoader().getResourceAsStream(configFilename);
            PropertyResourceBundle configResource =
                new PropertyResourceBundle(configFile);
            value = configResource.getString(property);
        } catch(FileNotFoundException fnfe) {
        	String msg = "The config file " + configFilename +
    		" was not found";
            log.error(msg, fnfe);
            throw new ConfigurationException(msg, fnfe);
        } catch(IOException ioe) {
        	String msg = "Error reading the config file  " + configFilename;
            log.error(msg, ioe);
            throw new ConfigurationException(msg, ioe);
        } catch(MissingResourceException mre) {
        	String msg = "Unable to find the value of the " +
    			"property " + property + " in the config file " + configFilename;
            log.error(msg, mre);
            throw new ConfigurationException(msg, mre);
        }
        return value;
    }
    
    /**
     * Read the path of the sherlock index directory
     * @return value of the property <code>sherlock.index.directory</code>
     */
    public static String getIndexDirectory()
            throws ConfigurationException {
        return getProperty(Constants.PROPERTY_INDEX_DIRECTORY);
    }

    /**
     * Read the path of the sherlock database scripts support.
     */
    public static String getSuppportDirectory()
    		throws ConfigurationException {
    	return Constants.SUPPORT_DIRECTORY;
    }
    
    public static String translateProperty(String value)
    		throws ConfigurationException {

		// replace variables
		String valueNormalized = value.replaceAll("\\$\\{sherlock\\.home\\}", "");
		return valueNormalized.replace('/', File.separatorChar);
    }
    
    /**
     * Read the store type. <code>internal</code> when using the hsqldb provided with the sherlock
     * distribution. <code>external</code> for using other kind of database like postgresql.
     * Note: when using an external database the scripts should be executed manually and the
     * config store properties setted accurately.
     * @return value of the property <code>sherlock.store.type</code>
     */
    public static String getStoreType()
            throws ConfigurationException {
        return getProperty(Constants.PROPERTY_STORE_TYPE);
    }
    
    /**
     * Read the class name of the driver to connect to the sherlock database
     * @return value of the property <code>sherlock.store.classdriver</code>
     */
    public static String getStoreClassDriver()
            throws ConfigurationException {
        return getProperty(Constants.PROPERTY_STORE_CLASSDRIVER);
    }
    
    /**
     * Read the sherlock database url to localize the database
     * @return value of the property <code>sherlock.store.url</code>
     */
    public static String getStoreURL()
            throws ConfigurationException {
        return getProperty(Constants.PROPERTY_STORE_URL);
    }
    
    /**
     * Reads the sherlock database user
     * @return Value of the property <code>sherlock.store.user</code>
     * @throws ConfigurationException a potential configuration error
     */
    public static String getStoreUser()
            throws ConfigurationException {
        return getProperty(Constants.PROPERTY_STORE_USER);
    }
    
    /**
     * Reads the sherlock database password
     * @return value of the property <code>sherlock.store.password</code>
     */
    public static String getStorePassword() throws ConfigurationException {
        return getProperty(Constants.PROPERTY_STORE_PASSWORD);
    }
    
    /**
     * Read the sherlock database catalog name
     * @return value of the property <code>sherlock.store.url</code>
     */
    public static String getStoreCatalog() {
    	try {
    		return getProperty(Constants.PROPERTY_STORE_CATALOG);
    	} catch(ConfigurationException ce) {
    		Logger log = Logger.getLogger(Configuration.class);
    		log.warn("Default catalog selected for sherlock repository");
        	return null;
    	}
    }
    
    /**
     * Reads the select statement to get the next value of a sequence
     * for primary key generation in the sherlock database
     * @return value of the property <code>sherlock.store.sequencequery</code>
     */
    public static String getStoreSequenceQuery() throws ConfigurationException {
        return getProperty(Constants.PROPERTY_STORE_SEQUENCE_QUERY);
    }
    
    /**
     * Reads the number of collectors for sherlock crawler
     * @return value of the property <code>sherlock.crawler.collectors</code>
     */
    public static int getCrawlerCollectors()
            throws ConfigurationException {
        String collectorsValue = getProperty(
        		Constants.PROPERTY_CRAWLER_COLLECTORS);
        int collectors = 0;
        try {
            collectors = Integer.parseInt(collectorsValue);
        } catch (NumberFormatException e) {
        	Logger log = Logger.getLogger(Configuration.class);
        	String msg = "The property " + Constants.PROPERTY_CRAWLER_COLLECTORS +
    			" in " + Constants.CONFIGURATION_SHERLOCK + " should be a " +
				"number";
        	log.error(msg);
            throw new ConfigurationException(msg);
        }
        if (collectors <= 0) {
        	Logger log = Logger.getLogger(Configuration.class);
        	String msg = "The property " + Constants.PROPERTY_CRAWLER_COLLECTORS +
				" in " + Constants.CONFIGURATION_SHERLOCK + "should be a " +
				"positive number";
        	log.error(msg);
            throw new ConfigurationException(msg);
        }
        return collectors;
    }

    public static int getMaxContentSize()
            throws ConfigurationException {
        String collectorsValue = getProperty(
        		Constants.PROPERTY_CRAWLER_MAX_CONTENT_SIZE);
        int collectors = 0;
        try {
            collectors = Integer.parseInt(collectorsValue);
        } catch (NumberFormatException e) {
        	Logger log = Logger.getLogger(Configuration.class);
        	String msg = "The property " +
				Constants.PROPERTY_CRAWLER_MAX_CONTENT_SIZE +
    			" in " + Constants.CONFIGURATION_SHERLOCK + " should be a " +
				"number";
        	log.error(msg);
            throw new ConfigurationException(msg);
        }
        if (collectors <= 0) {
        	Logger log = Logger.getLogger(Configuration.class);
        	String msg = "The property " +
				Constants.PROPERTY_CRAWLER_MAX_CONTENT_SIZE +
				" in " + Constants.CONFIGURATION_SHERLOCK + "should be a " +
				"positive number";
        	log.error(msg);
            throw new ConfigurationException(msg);
        }
        return collectors;
    }

    public static String getScopeConfigFilename()
    		throws ConfigurationException {
    	return Constants.CONFIG_DIRECTORY +
				"/" + Constants.CONFIGURATION_SCOPE;
    }

    public static String getSchedulerConfigFilename()
        	throws ConfigurationException {
        return Constants.CONFIG_DIRECTORY +
            	"/" + Constants.SCHEDULER_CONFIGURATION;
    }
    
    public static String getInitialPagesConfigFilename()
    		throws ConfigurationException {
    	return Constants.CONFIG_DIRECTORY +
				"/" + Constants.CONFIGURATION_INITIAL_PAGES;
    }
    
    public static String getLoggerConfigFilename()
    		throws ConfigurationException {
    	return Constants.CONFIG_DIRECTORY + "/" +
				Constants.LOGGER_CONFIGURATION;
    }
    
}
